using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using JGSY.CMS.LowCode.Platform.Domain.Interfaces;

namespace JGSY.CMS.LowCode.Platform.Infrastructure.Specifications
{
    /// <summary>
    /// 基础规范实现类
    /// </summary>
    /// <typeparam name="T">实体类型</typeparam>
    public abstract class BaseSpecification<T> : ISpecification<T>
    {
    public Expression<Func<T, bool>> Criteria { get; private set; } = _ => true;
        public List<Expression<Func<T, object>>> Includes { get; } = new List<Expression<Func<T, object>>>();
        public List<string> IncludeStrings { get; } = new List<string>();
        public Expression<Func<T, object>>? OrderBy { get; private set; }
        public Expression<Func<T, object>>? OrderByDescending { get; private set; }
        public Expression<Func<T, object>>? GroupBy { get; private set; }
        
        public bool IsPagingEnabled { get; private set; }
        public int Take { get; private set; }
        public int Skip { get; private set; }
        
        public bool IsCacheEnabled { get; private set; }
        public string? CacheKey { get; private set; }
        public TimeSpan? CacheExpiration { get; private set; }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="criteria">查询条件</param>
        protected BaseSpecification(Expression<Func<T, bool>>? criteria = null)
        {
            if (criteria != null)
            {
                Criteria = criteria;
            }
        }

        /// <summary>
        /// 添加Include
        /// </summary>
        /// <param name="includeExpression">Include表达式</param>
        /// <returns>当前规范对象</returns>
        protected virtual BaseSpecification<T> AddInclude(Expression<Func<T, object>> includeExpression)
        {
            Includes.Add(includeExpression);
            return this;
        }

        /// <summary>
        /// 添加Include字符串
        /// </summary>
        /// <param name="includeString">Include字符串</param>
        /// <returns>当前规范对象</returns>
        protected virtual BaseSpecification<T> AddInclude(string includeString)
        {
            IncludeStrings.Add(includeString);
            return this;
        }

        /// <summary>
        /// 应用排序
        /// </summary>
        /// <param name="orderByExpression">排序表达式</param>
        /// <returns>当前规范对象</returns>
        protected virtual BaseSpecification<T> ApplyOrderBy(Expression<Func<T, object>> orderByExpression)
        {
            OrderBy = orderByExpression;
            return this;
        }

        /// <summary>
        /// 应用降序排序
        /// </summary>
        /// <param name="orderByDescendingExpression">降序排序表达式</param>
        /// <returns>当前规范对象</returns>
        protected virtual BaseSpecification<T> ApplyOrderByDescending(Expression<Func<T, object>> orderByDescendingExpression)
        {
            OrderByDescending = orderByDescendingExpression;
            return this;
        }

        /// <summary>
        /// 应用分组
        /// </summary>
        /// <param name="groupByExpression">分组表达式</param>
        /// <returns>当前规范对象</returns>
        protected virtual BaseSpecification<T> ApplyGroupBy(Expression<Func<T, object>> groupByExpression)
        {
            GroupBy = groupByExpression;
            return this;
        }

        /// <summary>
        /// 应用分页
        /// </summary>
        /// <param name="skip">跳过记录数</param>
        /// <param name="take">获取记录数</param>
        /// <returns>当前规范对象</returns>
        protected virtual BaseSpecification<T> ApplyPaging(int skip, int take)
        {
            Skip = skip;
            Take = take;
            IsPagingEnabled = true;
            return this;
        }

        /// <summary>
        /// 启用缓存
        /// </summary>
        /// <param name="cacheKey">缓存键</param>
        /// <param name="expiration">过期时间</param>
        /// <returns>当前规范对象</returns>
        protected virtual BaseSpecification<T> EnableCache(string cacheKey, TimeSpan? expiration = null)
        {
            IsCacheEnabled = true;
            CacheKey = cacheKey;
            CacheExpiration = expiration ?? TimeSpan.FromMinutes(30);
            return this;
        }

        /// <summary>
        /// 设置查询条件
        /// </summary>
        /// <param name="criteria">查询条件</param>
        protected void SetCriteria(Expression<Func<T, bool>> criteria)
        {
            Criteria = criteria;
        }
    }

    /// <summary>
    /// 复合规范 - And操作
    /// </summary>
    /// <typeparam name="T">实体类型</typeparam>
    public class AndSpecification<T> : BaseSpecification<T>
    {
        public AndSpecification(ISpecification<T> left, ISpecification<T> right)
        {
            var leftExpression = left.Criteria;
            var rightExpression = right.Criteria;

            var parameter = Expression.Parameter(typeof(T));
            var leftVisitor = new ReplaceExpressionVisitor(leftExpression.Parameters[0], parameter);
            var rightVisitor = new ReplaceExpressionVisitor(rightExpression.Parameters[0], parameter);

            var leftBody = leftVisitor.Visit(leftExpression.Body);
            var rightBody = rightVisitor.Visit(rightExpression.Body);

            var andExpression = Expression.AndAlso(leftBody, rightBody);
            SetCriteria(Expression.Lambda<Func<T, bool>>(andExpression, parameter));
        }
    }

    /// <summary>
    /// 复合规范 - Or操作
    /// </summary>
    /// <typeparam name="T">实体类型</typeparam>
    public class OrSpecification<T> : BaseSpecification<T>
    {
        public OrSpecification(ISpecification<T> left, ISpecification<T> right)
        {
            var leftExpression = left.Criteria;
            var rightExpression = right.Criteria;

            var parameter = Expression.Parameter(typeof(T));
            var leftVisitor = new ReplaceExpressionVisitor(leftExpression.Parameters[0], parameter);
            var rightVisitor = new ReplaceExpressionVisitor(rightExpression.Parameters[0], parameter);

            var leftBody = leftVisitor.Visit(leftExpression.Body);
            var rightBody = rightVisitor.Visit(rightExpression.Body);

            var orExpression = Expression.OrElse(leftBody, rightBody);
            SetCriteria(Expression.Lambda<Func<T, bool>>(orExpression, parameter));
        }
    }

    /// <summary>
    /// 表达式访问器 - 用于替换参数
    /// </summary>
    public class ReplaceExpressionVisitor : ExpressionVisitor
    {
        private readonly Expression _oldValue;
        private readonly Expression _newValue;

        public ReplaceExpressionVisitor(Expression oldValue, Expression newValue)
        {
            _oldValue = oldValue;
            _newValue = newValue;
        }

        public override Expression Visit(Expression? node)
        {
            if (node == _oldValue)
                return _newValue;

            var visited = base.Visit(node);
            // base.Visit 可能返回 null，这里回退为原节点以确保非空返回
            return visited ?? node ?? Expression.Empty();
        }
    }

    /// <summary>
    /// 规范扩展方法
    /// </summary>
    public static class SpecificationExtensions
    {
        /// <summary>
        /// And操作
        /// </summary>
        public static ISpecification<T> And<T>(this ISpecification<T> left, ISpecification<T> right)
        {
            return new AndSpecification<T>(left, right);
        }

        /// <summary>
        /// Or操作
        /// </summary>
        public static ISpecification<T> Or<T>(this ISpecification<T> left, ISpecification<T> right)
        {
            return new OrSpecification<T>(left, right);
        }
    }
}
